
declare namespace RPGMakerMV {
    interface Motion {
        index: number;
        loop: boolean;
    }
}

//=============================================================================
// rpg_sprites.js v1.6.2
//=============================================================================

//-----------------------------------------------------------------------------
// Sprite_Base
//
// The sprite class with a feature which displays animations.

 class Sprite_Base extends Sprite {
    constructor(){
        super()
        this.initialize.apply(this, arguments);
    }
    initialize(): void {
        Sprite.prototype.initialize.call(this);
        this._animationSprites = [];
        this._effectTarget = this;
        this._hiding = false;
    };
    _animationSprites: Sprite_Animation[];
    _effectTarget: Sprite_Base;
    _hiding: boolean;

    update(): void{
        Sprite.prototype.update.call(this);
        this.updateVisibility();
        this.updateAnimationSprites();
    };
    hide(): void{
        this._hiding = true;
        this.updateVisibility();
    };
    show(): void{
        this._hiding = false;
        this.updateVisibility();
    };
    updateVisibility(): void{
        this.visible = !this._hiding;
    };
    updateAnimationSprites(): void{
        if (this._animationSprites.length > 0) {
            var sprites:any = this._animationSprites.clone();
            this._animationSprites = [];
            for (var i = 0; i < sprites.length; i++) {
                var sprite = sprites[i];
                if (sprite.isPlaying()) {
                    this._animationSprites.push(sprite);
                } else {
                    sprite.remove();
                }
            }
        }
    };
    startAnimation(animation: RPGMakerMV.DataAnimation, mirror: boolean, delay: number): void{
        var sprite = new Sprite_Animation();
        sprite.setup(this._effectTarget, animation, mirror, delay);
        this.parent.addChild(sprite);
        this._animationSprites.push(sprite);
    };
    isAnimationPlaying(): boolean{
        return this._animationSprites.length > 0;
    };
}

//-----------------------------------------------------------------------------
// Sprite_Button
//
// The sprite for displaying a button.

 class Sprite_Button extends Sprite {
    constructor(){
        super();
        this.initialize.apply(this, arguments);
    }
    initialize(): void{
        Sprite.prototype.initialize.call(this);
        this._touching = false;
        this._coldFrame = null;
        this._hotFrame = null;
        this._clickHandler = null;
    };
    _touching: boolean;
    _coldFrame: Rectangle;
    _hotFrame: Rectangle;
    _clickHandler: Function;

    update(): void{
        Sprite.prototype.update.call(this);
        this.updateFrame();
        this.processTouch();
    };
    updateFrame(): void{
        var frame;
        if (this._touching) {
            frame = this._hotFrame;
        } else {
            frame = this._coldFrame;
        }
        if (frame) {
            this.setFrame(frame.x, frame.y, frame.width, frame.height);
        }
    };
    setColdFrame(x: number, y: number, width: number, height: number): void{
        this._coldFrame = new Rectangle(x, y, width, height);
    };
    setHotFrame(x: number, y: number, width: number, height: number): void{
        this._hotFrame = new Rectangle(x, y, width, height);
    };
    setClickHandler(method: Function): void{
        this._clickHandler = method;
    };
    callClickHandler(): void{
        if (this._clickHandler) {
            this._clickHandler();
        }
    };
    processTouch(): void{
        if (this.isActive()) {
            if (TouchInput.isTriggered() && this.isButtonTouched()) {
                this._touching = true;
            }
            if (this._touching) {
                if (TouchInput.isReleased() || !this.isButtonTouched()) {
                    this._touching = false;
                    if (TouchInput.isReleased()) {
                        this.callClickHandler();
                    }
                }
            }
        } else {
            this._touching = false;
        }
    };
    isActive(): boolean{
        var node:any = this;
        while (node) {
            if (!node.visible) {
                return false;
            }
            node = node.parent;
        }
        return true;
    };
    isButtonTouched(): boolean{
        var x = this.canvasToLocalX(TouchInput.x);
        var y = this.canvasToLocalY(TouchInput.y);
        return x >= 0 && y >= 0 && x < this.width && y < this.height;
    };
    canvasToLocalX(x: number): number{
        var node:any = this;
        while (node) {
            x -= node.x;
            node = node.parent;
        }
        return x;
    };
    canvasToLocalY(y: number): number{
        var node:any = this;
        while (node) {
            y -= node.y;
            node = node.parent;
        }
        return y;
    };
}

//-----------------------------------------------------------------------------
// Sprite_Character
//
// The sprite for displaying a character.

 class Sprite_Character extends Sprite_Base {
    constructor(character?: Game_CharacterBase){
        super();
        this.initialize.apply(this, arguments);
    }
    initialize(character?: Game_CharacterBase): void{
        Sprite_Base.prototype.initialize.call(this);
        this.initMembers();
        this.setCharacter(character);
    };
    _character: Game_Character|any;
    _balloonSprite: Sprite_Balloon;
    _balloonDuration: number;
    _tilesetId: number;
    _upperBody: Sprite;
    _lowerBody: Sprite;

    initMembers(): void{
        this.anchor.x = 0.5;
        this.anchor.y = 1;
        this._character = null;
        this._balloonDuration = 0;
        this._tilesetId = 0;
        this._upperBody = null;
        this._lowerBody = null;
    };
    setCharacter(character: Game_CharacterBase|any): void{
        this._character = character;
    };
    update(): void{
        Sprite_Base.prototype.update.call(this);
        this.updateBitmap();
        this.updateFrame();
        this.updatePosition();
        this.updateAnimation();
        this.updateBalloon();
        this.updateOther();
    };
    updateVisibility(): void{
        Sprite_Base.prototype.updateVisibility.call(this);
        if (this._character.isTransparent()) {
            this.visible = false;
        }
    };
    isTile(): boolean{
        return this._character.tileId > 0;
    };
    tilesetBitmap(tileId: number): Bitmap{
        var tileset = $gameMap.tileset();
        var setNumber = 5 + Math.floor(tileId / 256);
        return ImageManager.loadTileset(tileset.tilesetNames[setNumber]);
    };
    updateBitmap(): void{
        if (this.isImageChanged()) {
            this._tilesetId = $gameMap.tilesetId();
            this._tileId = this._character.tileId();
            this._characterName = this._character.characterName();
            this._characterIndex = this._character.characterIndex();
            if (this._tileId > 0) {
                this.setTileBitmap();
            } else {
                this.setCharacterBitmap();
            }
        }
    };
    _tileId: number;
    _characterName: string;
    _characterIndex: number;
    isImageChanged(): boolean{
        return (this._tilesetId !== $gameMap.tilesetId() ||
                this._tileId !== this._character.tileId() ||
                this._characterName !== this._character.characterName() ||
                this._characterIndex !== this._character.characterIndex());
    };
    setTileBitmap(): void{
        this.bitmap = this.tilesetBitmap(this._tileId);
    };
    setCharacterBitmap(): void{
        this.bitmap = ImageManager.loadCharacter(this._characterName);
        this._isBigCharacter = ImageManager.isBigCharacter(this._characterName);
    };
    _isBigCharacter: boolean;
    updateFrame(): void{
        if (this._tileId > 0) {
            this.updateTileFrame();
        } else {
            this.updateCharacterFrame();
        }
    };
    updateTileFrame(): void{
        var pw = this.patternWidth();
        var ph = this.patternHeight();
        var sx = (Math.floor(this._tileId / 128) % 2 * 8 + this._tileId % 8) * pw;
        var sy = Math.floor(this._tileId % 256 / 8) % 16 * ph;
        this.setFrame(sx, sy, pw, ph);
    };
    updateCharacterFrame(): void{
        var pw = this.patternWidth();
        var ph = this.patternHeight();
        var sx = (this.characterBlockX() + this.characterPatternX()) * pw;
        var sy = (this.characterBlockY() + this.characterPatternY()) * ph;
        this.updateHalfBodySprites();
        if (this._bushDepth > 0) {
            var d = this._bushDepth;
            this._upperBody.setFrame(sx, sy, pw, ph - d);
            this._lowerBody.setFrame(sx, sy + ph - d, pw, d);
            this.setFrame(sx, sy, 0, ph);
        } else {
            this.setFrame(sx, sy, pw, ph);
        }
    };
    characterBlockX(): number{
        if (this._isBigCharacter) {
            return 0;
        } else {
            var index = this._character.characterIndex();
            return index % 4 * 3;
        }
    };
    characterBlockY(): number{
        if (this._isBigCharacter) {
            return 0;
        } else {
            var index = this._character.characterIndex();
            return Math.floor(index / 4) * 4;
        }
    };
    characterPatternX(): number {
        return this._character.pattern();
    };
    characterPatternY(): number{
        return (this._character.direction() - 2) / 2;
    };
    patternWidth(): number{
        if (this._tileId > 0) {
            return $gameMap.tileWidth();
        } else if (this._isBigCharacter) {
            return this.bitmap.width / 3;
        } else {
            return this.bitmap.width / 12;
        }
    };
    patternHeight(): number{
        if (this._tileId > 0) {
            return $gameMap.tileHeight();
        } else if (this._isBigCharacter) {
            return this.bitmap.height / 4;
        } else {
            return this.bitmap.height / 8;
        }
    };
    updateHalfBodySprites(): void{
        if (this._bushDepth > 0) {
            this.createHalfBodySprites();
            this._upperBody.bitmap = this.bitmap;
            this._upperBody.visible = true;
            this._upperBody.y = - this._bushDepth;
            this._lowerBody.bitmap = this.bitmap;
            this._lowerBody.visible = true;
            this._upperBody.setBlendColor(this.getBlendColor());
            this._lowerBody.setBlendColor(this.getBlendColor());
            this._upperBody.setColorTone(this.getColorTone());
            this._lowerBody.setColorTone(this.getColorTone());
        } else if (this._upperBody) {
            this._upperBody.visible = false;
            this._lowerBody.visible = false;
        }
    };
    createHalfBodySprites(): void {
        if (!this._upperBody) {
            this._upperBody = new Sprite();
            this._upperBody.anchor.x = 0.5;
            this._upperBody.anchor.y = 1;
            this.addChild(this._upperBody);
        }
        if (!this._lowerBody) {
            this._lowerBody = new Sprite();
            this._lowerBody.anchor.x = 0.5;
            this._lowerBody.anchor.y = 1;
            this._lowerBody.opacity = 128;
            this.addChild(this._lowerBody);
        }
    };
    updatePosition(): void {
        this.x = this._character.screenX();
        this.y = this._character.screenY();
        this.z = this._character.screenZ();
    };
    updateAnimation(): void {
        this.setupAnimation();
        if (!this.isAnimationPlaying()) {
            this._character.endAnimation();
        }
        if (!this.isBalloonPlaying()) {
            this._character.endBalloon();
        }
    };
    updateOther(): void {
        this.opacity = this._character.opacity();
        this.blendMode = this._character.blendMode();
        this._bushDepth = this._character.bushDepth();
    };
    _bushDepth: number;
    setupAnimation(): void {
        if (this._character.animationId() > 0) {
            var animation = $dataAnimations[this._character.animationId()];
            this.startAnimation(animation, false, 0);
            this._character.startAnimation();
        }
    };
    setupBalloon(): void {
        if (this._character.balloonId() > 0) {
            this.startBalloon();
            this._character.startBalloon();
        }
    };
    startBalloon(): void {
        if (!this._balloonSprite) {
            this._balloonSprite = new Sprite_Balloon();
        }
        this._balloonSprite.setup(this._character.balloonId());
        this.parent.addChild(this._balloonSprite);
    };
    updateBalloon(): void {
        this.setupBalloon();
        if (this._balloonSprite) {
            this._balloonSprite.x = this.x;
            this._balloonSprite.y = this.y - this.height;
            if (!this._balloonSprite.isPlaying()) {
                this.endBalloon();
            }
        }
    };
    endBalloon(): void {
        if (this._balloonSprite) {
            this.parent.removeChild(this._balloonSprite);
            this._balloonSprite = null;
        }
    };
    isBalloonPlaying(): boolean {
        return !!this._balloonSprite;
    };
}

//-----------------------------------------------------------------------------
// Sprite_Battler
//
// The superclass of Sprite_Actor and Sprite_Enemy.

 class Sprite_Battler extends Sprite_Base {
    constructor(){
        super();
        this.initialize.apply(this, arguments);
    }
    initialize(battler?: Game_Battler): void {
        Sprite_Base.prototype.initialize.call(this);
        this.initMembers();
        this.setBattler(battler);
    };
    _battler: Game_Battler|any;
    _damages: Sprite_Damage[];
    _homeX: number;
    _homeY: number;
    _offsetX: number;
    _offsetY: number;
    _targetOffsetX: number;
    _targetOffsetY: number;
    _movementDuration: number;
    _selectionEffectCount: number;

    initMembers(): void{
        this.anchor.x = 0.5;
        this.anchor.y = 1;
        this._battler = null;
        this._damages = [];
        this._homeX = 0;
        this._homeY = 0;
        this._offsetX = 0;
        this._offsetY = 0;
        this._targetOffsetX = NaN;
        this._targetOffsetY = NaN;
        this._movementDuration = 0;
        this._selectionEffectCount = 0;
    };
    setBattler(battler: Game_Battler): void{
        this._battler = battler;
    };
    setHome(x: number, y: number): void{
        this._homeX = x;
        this._homeY = y;
        this.updatePosition();
    };
    update(): void{
        Sprite_Base.prototype.update.call(this);
        if (this._battler) {
            this.updateMain();
            this.updateAnimation();
            this.updateDamagePopup();
            this.updateSelectionEffect();
        } else {
            this.bitmap = null;
        }
    };
    updateVisibility(): void{
        Sprite_Base.prototype.updateVisibility.call(this);
        if (!this._battler || !this._battler.isSpriteVisible()) {
            this.visible = false;
        }
    };
    updateMain(): void{
        if (this._battler.isSpriteVisible()) {
            this.updateBitmap();
            this.updateFrame();
        }
        this.updateMove();
        this.updatePosition();
    };
    updateBitmap(): void{
    };
    updateFrame(): void{
    };
    updateMove(): void{
        if (this._movementDuration > 0) {
            var d = this._movementDuration;
            this._offsetX = (this._offsetX * (d - 1) + this._targetOffsetX) / d;
            this._offsetY = (this._offsetY * (d - 1) + this._targetOffsetY) / d;
            this._movementDuration--;
            if (this._movementDuration === 0) {
                this.onMoveEnd();
            }
        }
    };
    updatePosition(): void{
        this.x = this._homeX + this._offsetX;
        this.y = this._homeY + this._offsetY;
    };
    updateAnimation(): void{
        this.setupAnimation();
    };
    updateDamagePopup(): void {
        this.setupDamagePopup();
        if (this._damages.length > 0) {
            for (var i = 0; i < this._damages.length; i++) {
                this._damages[i].update();
            }
            if (!this._damages[0].isPlaying()) {
                this.parent.removeChild(this._damages[0]);
                this._damages.shift();
            }
        }
    };
    updateSelectionEffect(): void {
        var target = this._effectTarget;
        if (this._battler.isSelected()) {
            this._selectionEffectCount++;
            if (this._selectionEffectCount % 30 < 15) {
                target.setBlendColor([255, 255, 255, 64]);
            } else {
                target.setBlendColor([0, 0, 0, 0]);
            }
        } else if (this._selectionEffectCount > 0) {
            this._selectionEffectCount = 0;
            target.setBlendColor([0, 0, 0, 0]);
        }
    };
    setupAnimation(): void {
        while (this._battler.isAnimationRequested()) {
            var data = this._battler.shiftAnimation();
            var animation = $dataAnimations[data.animationId];
            var mirror = data.mirror;
            var delay = animation.position === 3 ? 0 : data.delay;
            this.startAnimation(animation, mirror, delay);
            for (var i = 0; i < this._animationSprites.length; i++) {
                var sprite = this._animationSprites[i];
                sprite.visible = this._battler.isSpriteVisible();
            }
        }
    };
    setupDamagePopup(): void {
        if (this._battler.isDamagePopupRequested()) {
            if (this._battler.isSpriteVisible()) {
                var sprite = new Sprite_Damage();
                sprite.x = this.x + this.damageOffsetX();
                sprite.y = this.y + this.damageOffsetY();
                sprite.setup(this._battler);
                this._damages.push(sprite);
                this.parent.addChild(sprite);
            }
            this._battler.clearDamagePopup();
            this._battler.clearResult();
        }
    };
    damageOffsetX(): number{
        return 0;
    };
    damageOffsetY(): number{
        return 0;
    };
    startMove(x: number, y: number, duration: number): void{
        if (this._targetOffsetX !== x || this._targetOffsetY !== y) {
            this._targetOffsetX = x;
            this._targetOffsetY = y;
            this._movementDuration = duration;
            if (duration === 0) {
                this._offsetX = x;
                this._offsetY = y;
            }
        }
    };
    onMoveEnd(): void{
    };
    isEffecting(): boolean{
        return false;
    };
    isMoving(): boolean{
        return this._movementDuration > 0;
    };
    inHomePosition(): boolean{
        return this._offsetX === 0 && this._offsetY === 0;
    };
}

//-----------------------------------------------------------------------------
// Sprite_Actor
//
// The sprite for displaying an actor.

 class Sprite_Actor extends Sprite_Battler {
    _actor: any;
    constructor(){
        super();
        this.initialize.apply(this, arguments);
    }

    static MOTIONS: {
        walk:     { index: 0,  loop: true  },
        wait:     { index: 1,  loop: true  },
        chant:    { index: 2,  loop: true  },
        guard:    { index: 3,  loop: true  },
        damage:   { index: 4,  loop: false },
        evade:    { index: 5,  loop: false },
        thrust:   { index: 6,  loop: false },
        swing:    { index: 7,  loop: false },
        missile:  { index: 8,  loop: false },
        skill:    { index: 9,  loop: false },
        spell:    { index: 10, loop: false },
        item:     { index: 11, loop: false },
        escape:   { index: 12, loop: true  },
        victory:  { index: 13, loop: true  },
        dying:    { index: 14, loop: true  },
        abnormal: { index: 15, loop: true  },
        sleep:    { index: 16, loop: true  },
        dead:     { index: 17, loop: true  }
    } & { [key: string]: RPGMakerMV.Motion };

    initialize(battler?: Game_Actor): void{
        Sprite_Battler.prototype.initialize.call(this, battler);
        this.moveToStartPosition();
    };
    initMembers(): void {
        Sprite_Battler.prototype.initMembers.call(this);
        this._battlerName = '';
        this._motion = null;
        this._motionCount = 0;
        this._pattern = 0;
        this.createShadowSprite();
        this.createWeaponSprite();
        this.createMainSprite();
        this.createStateSprite();
    };
    _battlerName: string;
    _motion: RPGMakerMV.Motion;
    _motionCount: number;
    _pattern: number;

    createMainSprite(): void {
        this._mainSprite = new Sprite_Base();
        this._mainSprite.anchor.x = 0.5;
        this._mainSprite.anchor.y = 1;
        this.addChild(this._mainSprite);
        this._effectTarget = this._mainSprite;
    };
    _mainSprite: Sprite_Base;
    _effectTarget: Sprite_Base;
    createShadowSprite(): void{
        this._shadowSprite = new Sprite();
        this._shadowSprite.bitmap = ImageManager.loadSystem('Shadow2');
        this._shadowSprite.anchor.x = 0.5;
        this._shadowSprite.anchor.y = 0.5;
        this._shadowSprite.y = -2;
        this.addChild(this._shadowSprite);
    };
    _shadowSprite: Sprite;
    createWeaponSprite(): void {
        this._weaponSprite = new Sprite_Weapon();
        this.addChild(this._weaponSprite);
    };
    _weaponSprite: Sprite_Weapon;
    createStateSprite(): void{
        this._stateSprite = new Sprite_StateOverlay();
        this.addChild(this._stateSprite);
    };
    _stateSprite: Sprite_StateOverlay;
    setBattler(battler: Game_Actor): void {
        Sprite_Battler.prototype.setBattler.call(this, battler);
        var changed = (battler !== this._actor);
        if (changed) {
            this._actor = battler;
            if (battler) {
                this.setActorHome(battler.index());
            }
            this.startEntryMotion();
            this._stateSprite.setup(battler);
        }
    };
    moveToStartPosition(): void {
        this.startMove(300, 0, 0);
    };
    setActorHome(index: number): void {
        this.setHome(600 + index * 32, 280 + index * 48);
    };
    update(): void {
        Sprite_Battler.prototype.update.call(this);
        this.updateShadow();
        if (this._actor) {
            this.updateMotion();
        }
    };
    updateShadow(): void {
        this._shadowSprite.visible = !!this._actor;
    };
    updateMain(): void {
        Sprite_Battler.prototype.updateMain.call(this);
        if (this._actor.isSpriteVisible() && !this.isMoving()) {
            this.updateTargetPosition();
        }
    };
    setupMotion(): void {
        if (this._actor.isMotionRequested()) {
            this.startMotion(this._actor.motionType());
            this._actor.clearMotion();
        }
    };
    setupWeaponAnimation(): void {
        if (this._actor.isWeaponAnimationRequested()) {
            this._weaponSprite.setup(this._actor.weaponImageId());
            this._actor.clearWeaponAnimation();
        }
    };
    startMotion(motionType: string): void {
        var newMotion = Sprite_Actor.MOTIONS[motionType];
        if (this._motion !== newMotion) {
            this._motion = newMotion;
            this._motionCount = 0;
            this._pattern = 0;
        }
    };
    updateTargetPosition(): void {
        if (this._actor.isInputting() || this._actor.isActing()) {
            this.stepForward();
        } else if (this._actor.canMove() && BattleManager.isEscaped()) {
            this.retreat();
        } else if (!this.inHomePosition()) {
            this.stepBack();
        }
    };
    updateBitmap(): void {
        Sprite_Battler.prototype.updateBitmap.call(this);
        var name = this._actor.battlerName();
        if (this._battlerName !== name) {
            this._battlerName = name;
            this._mainSprite.bitmap = ImageManager.loadSvActor(name);
        }
    };
    updateFrame(): void {
        Sprite_Battler.prototype.updateFrame.call(this);
        var bitmap = this._mainSprite.bitmap;
        if (bitmap) {
            var motionIndex = this._motion ? this._motion.index : 0;
            var pattern = this._pattern < 3 ? this._pattern : 1;
            var cw = bitmap.width / 9;
            var ch = bitmap.height / 6;
            var cx = Math.floor(motionIndex / 6) * 3 + pattern;
            var cy = motionIndex % 6;
            this._mainSprite.setFrame(cx * cw, cy * ch, cw, ch);
        }
    };
    updateMove(): void {
        var bitmap = this._mainSprite.bitmap;
        if (!bitmap || bitmap.isReady()) {
            Sprite_Battler.prototype.updateMove.call(this);
        }
    };
    updateMotion(): void {
        this.setupMotion();
        this.setupWeaponAnimation();
        if (this._actor.isMotionRefreshRequested()) {
            this.refreshMotion();
            this._actor.clearMotion();
        }
        this.updateMotionCount();
    };
    updateMotionCount(): void {
        if (this._motion && ++this._motionCount >= this.motionSpeed()) {
            if (this._motion.loop) {
                this._pattern = (this._pattern + 1) % 4;
            } else if (this._pattern < 2) {
                this._pattern++;
            } else {
                this.refreshMotion();
            }
            this._motionCount = 0;
        }
    };
    motionSpeed(): number {
        return 12;
    };
    refreshMotion(): void {
        var actor = this._actor;
        var motionGuard = Sprite_Actor.MOTIONS['guard'];
        if (actor) {
            if (this._motion === motionGuard && !BattleManager.isInputting()) {
                    return;
            }
            var stateMotion = actor.stateMotionIndex();
            if (actor.isInputting() || actor.isActing()) {
                this.startMotion('walk');
            } else if (stateMotion === 3) {
                this.startMotion('dead');
            } else if (stateMotion === 2) {
                this.startMotion('sleep');
            } else if (actor.isChanting()) {
                this.startMotion('chant');
            } else if (actor.isGuard() || actor.isGuardWaiting()) {
                this.startMotion('guard');
            } else if (stateMotion === 1) {
                this.startMotion('abnormal');
            } else if (actor.isDying()) {
                this.startMotion('dying');
            } else if (actor.isUndecided()) {
                this.startMotion('walk');
            } else {
                this.startMotion('wait');
            }
        }
    };
    startEntryMotion(): void {
        if (this._actor && this._actor.canMove()) {
            this.startMotion('walk');
            this.startMove(0, 0, 30);
        } else if (!this.isMoving()) {
            this.refreshMotion();
            this.startMove(0, 0, 0);
        }
    };
    stepForward(): void {
        this.startMove(-48, 0, 12);
    };
    stepBack(): void{
        this.startMove(0, 0, 12);
    };
    retreat(): void{
        this.startMove(300, 0, 30);
    };
    onMoveEnd(): void{
        Sprite_Battler.prototype.onMoveEnd.call(this);
        if (!BattleManager.isBattleEnd()) {
            this.refreshMotion();
        }
    };
    damageOffsetX(): number{
        return -32;
    };
    damageOffsetY(): number{
        return 0;
    };
}

//-----------------------------------------------------------------------------
// Sprite_Enemy
//
// The sprite for displaying an enemy.

 class Sprite_Enemy extends Sprite_Battler {
    constructor(enemies? : any){
        super();
        this.initialize.apply(this, arguments);
    }
    initialize(battler?: Game_Enemy): void{
        Sprite_Battler.prototype.initialize.call(this, battler);
    };
    initMembers(): void {
        Sprite_Battler.prototype.initMembers.call(this);
        this._enemy = null;
        this._appeared = false;
        this._battlerName = '';
        this._battlerHue = 0;
        this._effectType = null;
        this._effectDuration = 0;
        this._shake = 0;
        this.createStateIconSprite();
    };
    _enemy: Game_Enemy;
    _appeared: boolean;
    _battlerName: string;
    _battlerHue: number;
    _effectType: string;
    _effectDuration: number;
    _shake: number;
    createStateIconSprite(): void {
        this._stateIconSprite = new Sprite_StateIcon();
        this.addChild(this._stateIconSprite);
    };
    _stateIconSprite: Sprite_StateIcon;
    setBattler(battler: Game_Enemy): void {
        Sprite_Battler.prototype.setBattler.call(this, battler);
        this._enemy = battler;
        this.setHome(battler.screenX(), battler.screenY());
        this._stateIconSprite.setup(battler);
    };
    update(): void {
        Sprite_Battler.prototype.update.call(this);
        if (this._enemy) {
            this.updateEffect();
            this.updateStateSprite();
        }
    };
    updateBitmap(): void {
        Sprite_Battler.prototype.updateBitmap.call(this);
        var name = this._enemy.battlerName();
        var hue = this._enemy.battlerHue();
        if (this._battlerName !== name || this._battlerHue !== hue) {
            this._battlerName = name;
            this._battlerHue = hue;
            this.loadBitmap(name, hue);
            this.initVisibility();
        }
    };
    loadBitmap(name: string, hue: number): void {
        if ($gameSystem.isSideView()) {
            this.bitmap = ImageManager.loadSvEnemy(name, hue);
        } else {
            this.bitmap = ImageManager.loadEnemy(name, hue);
        }
    };
    updateFrame(): void {
        Sprite_Battler.prototype.updateFrame.call(this);
        var frameHeight = this.bitmap.height;
        if (this._effectType === 'bossCollapse') {
            frameHeight = this._effectDuration;
        }
        this.setFrame(0, 0, this.bitmap.width, frameHeight);
    };
    updatePosition(): void {
        Sprite_Battler.prototype.updatePosition.call(this);
        this.x += this._shake;
    };
    updateStateSprite(): void {
        this._stateIconSprite.y = -Math.round((this.bitmap.height + 40) * 0.9);
        if (this._stateIconSprite.y < 20 - this.y) {
            this._stateIconSprite.y = 20 - this.y;
        }
    };
    initVisibility(): void {
        this._appeared = this._enemy.isAlive();
        if (!this._appeared) {
            this.opacity = 0;
        }
    };
    setupEffect(): void {
        if (this._appeared && this._enemy.isEffectRequested()) {
            this.startEffect(this._enemy.effectType());
            this._enemy.clearEffect();
        }
        if (!this._appeared && this._enemy.isAlive()) {
            this.startEffect('appear');
        } else if (this._appeared && this._enemy.isHidden()) {
            this.startEffect('disappear');
        }
    };
    startEffect(effectType: string): void {
        this._effectType = effectType;
        switch (this._effectType) {
        case 'appear':
            this.startAppear();
            break;
        case 'disappear':
            this.startDisappear();
            break;
        case 'whiten':
            this.startWhiten();
            break;
        case 'blink':
            this.startBlink();
            break;
        case 'collapse':
            this.startCollapse();
            break;
        case 'bossCollapse':
            this.startBossCollapse();
            break;
        case 'instantCollapse':
            this.startInstantCollapse();
            break;
        }
        this.revertToNormal();
    };
    startAppear(): void {
        this._effectDuration = 16;
        this._appeared = true;
    };
    startDisappear(): void {
        this._effectDuration = 32;
        this._appeared = false;
    };
    startWhiten(): void {
        this._effectDuration = 16;
    };
    startBlink(): void {
        this._effectDuration = 20;
    };
    startCollapse(): void {
        this._effectDuration = 32;
        this._appeared = false;
    };
    startBossCollapse(): void {
        this._effectDuration = this.bitmap.height;
        this._appeared = false;
    };
    startInstantCollapse(): void {
        this._effectDuration = 16;
        this._appeared = false;
    };
    updateEffect(): void {
        this.setupEffect();
        if (this._effectDuration > 0) {
            this._effectDuration--;
            switch (this._effectType) {
            case 'whiten':
                this.updateWhiten();
                break;
            case 'blink':
                this.updateBlink();
                break;
            case 'appear':
                this.updateAppear();
                break;
            case 'disappear':
                this.updateDisappear();
                break;
            case 'collapse':
                this.updateCollapse();
                break;
            case 'bossCollapse':
                this.updateBossCollapse();
                break;
            case 'instantCollapse':
                this.updateInstantCollapse();
                break;
            }
            if (this._effectDuration === 0) {
                this._effectType = null;
            }
        }
    };
    isEffecting(): boolean {
        return this._effectType !== null;
    };
    revertToNormal(): void {
        this._shake = 0;
        this.blendMode = 0;
        this.opacity = 255;
        this.setBlendColor([0, 0, 0, 0]);
    };
    updateWhiten(): void {
        var alpha = 128 - (16 - this._effectDuration) * 10;
        this.setBlendColor([255, 255, 255, alpha]);
    };
    updateBlink(): void {
        this.opacity = (this._effectDuration % 10 < 5) ? 255 : 0;
    };
    updateAppear(): void {
        this.opacity = (16 - this._effectDuration) * 16;
    };
    updateDisappear(): void {
        this.opacity = 256 - (32 - this._effectDuration) * 10;
    };
    updateCollapse(): void {
        this.blendMode = Graphics.BLEND_ADD;
        this.setBlendColor([255, 128, 128, 128]);
        this.opacity *= this._effectDuration / (this._effectDuration + 1);
    };
    updateBossCollapse(): void {
        this._shake = this._effectDuration % 2 * 4 - 2;
        this.blendMode = Graphics.BLEND_ADD;
        this.opacity *= this._effectDuration / (this._effectDuration + 1);
        this.setBlendColor([255, 255, 255, 255 - this.opacity]);
        if (this._effectDuration % 20 === 19) {
            SoundManager.playBossCollapse2();
        }
    };
    updateInstantCollapse(): void {
        this.opacity = 0;
    };
    damageOffsetX(): number {
        return 0;
    };
    damageOffsetY(): number {
        return -8;
    };
}

//-----------------------------------------------------------------------------
// Sprite_Animation
//
// The sprite for displaying an animation.

 class Sprite_Animation extends Sprite {
    constructor(){
        super();
        this.initialize.apply(this, arguments);
    }
    initialize(): void{
        Sprite.prototype.initialize.call(this);
        this._reduceArtifacts = true;
        this.initMembers();
    };
    initMembers(): void {
        this._target = null;
        this._animation = null;
        this._mirror = false;
        this._delay = 0;
        this._rate = 4;
        this._duration = 0;
        this._flashColor = [0, 0, 0, 0];
        this._flashDuration = 0;
        this._screenFlashDuration = 0;
        this._hidingDuration = 0;
        this._bitmap1 = null;
        this._bitmap2 = null;
        this._cellSprites = [];
        this._screenFlashSprite = null;
        this._duplicated = false;
        this.z = 8;
    };
    _reduceArtifacts: boolean;
    _target: Sprite_Base;
    _animation: RPGMakerMV.DataAnimation|any;
    _mirror: boolean;
    _delay: number;
    _rate: number;
    _duration: number;
    _flashColor: number[]|any;
    _flashDuration: number;
    _screenFlashDuration: number;
    _hidingDuration: number;
    _bitmap1: Bitmap;
    _bitmap2: Bitmap;
    _cellSprites: Sprite[];
    _screenFlashSprite: ScreenSprite;
    _duplicated: boolean;
    static _checker1 = {};
    static _checker2 = {};

    setup(target: Sprite_Base, animation: RPGMakerMV.DataAnimation, mirror: boolean, delay: number): void {
        this._target = target;
        this._animation = animation;
        this._mirror = mirror;
        this._delay = delay;
        if (this._animation) {
            this.remove();
            this.setupRate();
            this.setupDuration();
            this.loadBitmaps();
            this.createSprites();
        }
    };
    remove(): void{
        if (this.parent && this.parent.removeChild(this)) {
            this._target.setBlendColor([0, 0, 0, 0]);
            this._target.show();
        }
    };
    setupRate(): void {
        this._rate = 4;
    };
    
    setupDuration(): void {
        this._duration = this._animation.frames.length * this._rate + 1;
    };
    update(): void {
        Sprite.prototype.update.call(this);
        this.updateMain();
        this.updateFlash();
        this.updateScreenFlash();
        this.updateHiding();
        Sprite_Animation._checker1 = {};
        Sprite_Animation._checker2 = {};
    };
    updateFlash(): void {
        if (this._flashDuration > 0) {
            var d = this._flashDuration--;
            this._flashColor[3] *= (d - 1) / d;
            this._target.setBlendColor(this._flashColor);
        }
    };
    updateScreenFlash(): void {
        if (this._screenFlashDuration > 0) {
            var d = this._screenFlashDuration--;
            if (this._screenFlashSprite) {
                this._screenFlashSprite.x = -this.absoluteX();
                this._screenFlashSprite.y = -this.absoluteY();
                this._screenFlashSprite.opacity *= (d - 1) / d;
                this._screenFlashSprite.visible = (this._screenFlashDuration > 0);
            }
        }
    };
    absoluteX(): number {
        var x = 0;
        var object:any = this;
        while (object) {
            x += object.x;
            object = object.parent;
        }
        return x;
    };
    absoluteY(): number {
        var y = 0;
        var object:any = this;
        while (object) {
            y += object.y;
            object = object.parent;
        }
        return y;
    };
    updateHiding(): void {
        if (this._hidingDuration > 0) {
            this._hidingDuration--;
            if (this._hidingDuration === 0) {
                this._target.show();
            }
        }
    };
    isPlaying(): boolean {
        return this._duration > 0;
    };
    loadBitmaps(): void {
        var name1 = this._animation.animation1Name;
        var name2 = this._animation.animation2Name;
        var hue1 = this._animation.animation1Hue;
        var hue2 = this._animation.animation2Hue;
        this._bitmap1 = ImageManager.loadAnimation(name1, hue1);
        this._bitmap2 = ImageManager.loadAnimation(name2, hue2);
    };
    isReady(): boolean {
        return this._bitmap1 && this._bitmap1.isReady() && this._bitmap2 && this._bitmap2.isReady();
    };
    createSprites(): void {
        if (!Sprite_Animation._checker2[this._animation]) {
            this.createCellSprites();
            if (this._animation.position === 3) {
                Sprite_Animation._checker2[this._animation] = true;
            }
            this.createScreenFlashSprite();
        }
        if (Sprite_Animation._checker1[this._animation]) {
            this._duplicated = true;
        } else {
            this._duplicated = false;
            if (this._animation.position === 3) {
                Sprite_Animation._checker1[this._animation] = true;
            }
        }
    };
    createCellSprites(): void {
        this._cellSprites = [];
        for (var i = 0; i < 16; i++) {
            var sprite = new Sprite();
            sprite.anchor.x = 0.5;
            sprite.anchor.y = 0.5;
            this._cellSprites.push(sprite);
            this.addChild(sprite);
        }
    };
    createScreenFlashSprite(): void {
        this._screenFlashSprite = new ScreenSprite();
        this.addChild(this._screenFlashSprite);
    };
    updateMain(): void {
        if (this.isPlaying() && this.isReady()) {
            if (this._delay > 0) {
                this._delay--;
            } else {
                this._duration--;
                this.updatePosition();
                if (this._duration % this._rate === 0) {
                    this.updateFrame();
                }
            }
        }
    };
    updatePosition(): void {
        if (this._animation.position === 3) {
            this.x = this.parent.width / 2;
            this.y = this.parent.height / 2;
        } else {
            var parent = this._target.parent;
            var grandparent = parent ? parent.parent : null;
            this.x = this._target.x;
            this.y = this._target.y;
            if (this.parent === grandparent) {
                this.x += parent.x;
                this.y += parent.y;
            }
            if (this._animation.position === 0) {
                this.y -= this._target.height;
            } else if (this._animation.position === 1) {
                this.y -= this._target.height / 2;
            }
        }
    };
    updateFrame(): void {
        if (this._duration > 0) {
            var frameIndex:any = this.currentFrameIndex();
            this.updateAllCellSprites(this._animation.frames[frameIndex]);
            this._animation.timings.forEach((timing: RPGMakerMV.AnimationTiming) => {
                if (timing.frame === frameIndex) {
                    this.processTimingData(timing);
                }
            });
        }
    };
    currentFrameIndex(): void|any {
        return (this._animation.frames.length -
                Math.floor((this._duration + this._rate - 1) / this._rate));
    };
    updateAllCellSprites(frame: number[][]): void {
        for (var i = 0; i < this._cellSprites.length; i++) {
            var sprite = this._cellSprites[i];
            if (i < frame.length) {
                this.updateCellSprite(sprite, frame[i]);
            } else {
                sprite.visible = false;
            }
        }
    };
    updateCellSprite(sprite: Sprite, cell: number[]): void {
        var pattern = cell[0];
        if (pattern >= 0) {
            var sx = pattern % 5 * 192;
            var sy = Math.floor(pattern % 100 / 5) * 192;
            var mirror = this._mirror;
            sprite.bitmap = pattern < 100 ? this._bitmap1 : this._bitmap2;
            sprite.setFrame(sx, sy, 192, 192);
            sprite.x = cell[1];
            sprite.y = cell[2];
            sprite.rotation = cell[4] * Math.PI / 180;
            sprite.scale.x = cell[3] / 100;
    
            if(cell[5]){
                sprite.scale.x *= -1;
            }
            if(mirror){
                sprite.x *= -1;
                sprite.rotation *= -1;
                sprite.scale.x *= -1;
            }
    
            sprite.scale.y = cell[3] / 100;
            sprite.opacity = cell[6];
            sprite.blendMode = cell[7];
            sprite.visible = true;
        } else {
            sprite.visible = false;
        }
    };
    processTimingData(timing: RPGMakerMV.AnimationTiming): void {
        var duration = timing.flashDuration * this._rate;
        switch (timing.flashScope) {
        case 1:
            this.startFlash(timing.flashColor, duration);
            break;
        case 2:
            this.startScreenFlash(timing.flashColor, duration);
            break;
        case 3:
            this.startHiding(duration);
            break;
        }
        if (!this._duplicated && timing.se) {
            AudioManager.playSe(timing.se);
        }
    };
    startFlash(color: number[], duration: number): void{
        this._flashColor = color.clone();
        this._flashDuration = duration;
    };
    startScreenFlash(color: number[], duration: number): void {
        this._screenFlashDuration = duration;
        if (this._screenFlashSprite) {
            this._screenFlashSprite.setColor(color[0], color[1], color[2]);
            this._screenFlashSprite.opacity = color[3];
        }
    };
    startHiding(duration: number): void {
        this._hidingDuration = duration;
        this._target.hide();
    };
}

//-----------------------------------------------------------------------------
// Sprite_Damage
//
// The sprite for displaying a popup damage.

 class Sprite_Damage extends Sprite {
    constructor(){
        super();
        this.initialize.apply(this, arguments);
    }
    initialize(): void {
        Sprite.prototype.initialize.call(this);
        this._duration = 90;
        this._flashColor = [0, 0, 0, 0];
        this._flashDuration = 0;
        this._damageBitmap = ImageManager.loadSystem('Damage');
    };
    _duration: number;
    _flashColor: number[];
    _flashDuration: number;
    _damageBitmap: Bitmap;

    setup(target: Game_Battler): void {
        var result = target.result();
        if (result.missed || result.evaded) {
            this.createMiss();
        } else if (result.hpAffected) {
            this.createDigits(0, result.hpDamage);
        } else if (target.isAlive() && result.mpDamage !== 0) {
            this.createDigits(2, result.mpDamage);
        }
        if (result.critical) {
            this.setupCriticalEffect();
        }
    };
    setupCriticalEffect(): void {
        this._flashColor = [255, 0, 0, 160];
        this._flashDuration = 60;
    };
    digitWidth(): number {
        return this._damageBitmap ? this._damageBitmap.width / 10 : 0;
    };
    digitHeight(): number {
        return this._damageBitmap ? this._damageBitmap.height / 5 : 0;
    };
    createMiss(): void {
        var w = this.digitWidth();
        var h = this.digitHeight();
        var sprite:any = this.createChildSprite();
        sprite.setFrame(0, 4 * h, 4 * w, h);
        sprite.dy = 0;
    };
    createDigits(baseRow: number, value: number): void {
        var string = Math.abs(value).toString();
        var row = baseRow + (value < 0 ? 1 : 0);
        var w = this.digitWidth();
        var h = this.digitHeight();
        for (var i = 0; i < string.length; i++) {
            var sprite:any = this.createChildSprite();
            var n = Number(string[i]);
            sprite.setFrame(n * w, row * h, w, h);
            sprite.x = (i - (string.length - 1) / 2) * w;
            sprite.dy = -i;
        }
    };
    createChildSprite(): Sprite {
        var sprite:any = new Sprite();
        sprite.bitmap = this._damageBitmap;
        sprite.anchor.x = 0.5;
        sprite.anchor.y = 1;
        sprite.y = -40;
        sprite.ry = sprite.y;
        this.addChild(sprite);
        return sprite;
    };
    update(): void {
        Sprite.prototype.update.call(this);
        if (this._duration > 0) {
            this._duration--;
            for (var i = 0; i < this.children.length; i++) {
                this.updateChild(this.children[i]);
            }
        }
        this.updateFlash();
        this.updateOpacity();
    };
    updateChild(sprite: Sprite|any): void {
        sprite.dy += 0.5;
        sprite.ry += sprite.dy;
        if (sprite.ry >= 0) {
            sprite.ry = 0;
            sprite.dy *= -0.6;
        }
        sprite.y = Math.round(sprite.ry);
        sprite.setBlendColor(this._flashColor);
    };
    updateFlash(): void {
        if (this._flashDuration > 0) {
            var d = this._flashDuration--;
            this._flashColor[3] *= (d - 1) / d;
        }
    };
    updateOpacity(): void {
        if (this._duration < 10) {
            this.opacity = 255 * this._duration / 10;
        }
    };
    isPlaying(): boolean {
        return this._duration > 0;
    };
}

//-----------------------------------------------------------------------------
// Sprite_StateIcon
//
// The sprite for displaying state icons.

 class Sprite_StateIcon extends Sprite {
    constructor(){
        super();
        this.initialize.apply(this, arguments);
    }
    initialize(): void{
        Sprite.prototype.initialize.call(this);
        this.initMembers();
        this.loadBitmap();
    };
    static _iconWidth: number = 32;
    static _iconHeight: number = 32;

    initMembers(): void{
        this._battler = null;
        this._iconIndex = 0;
        this._animationCount = 0;
        this._animationIndex = 0;
        this.anchor.x = 0.5;
        this.anchor.y = 0.5;
    };
    _battler: Game_Battler;
    _iconIndex: number;
    _animationCount: number;
    _animationIndex: number;
    loadBitmap(): void{
        this.bitmap = ImageManager.loadSystem('IconSet');
        this.setFrame(0, 0, 0, 0);
    };
    setup(battler: Game_Battler): void{
        this._battler = battler;
    };
    update(): void {
        Sprite.prototype.update.call(this);
        this._animationCount++;
        if (this._animationCount >= this.animationWait()) {
            this.updateIcon();
            this.updateFrame();
            this._animationCount = 0;
        }
    };
    animationWait(): number {
        return 40;
    };
    updateIcon(): void {
        var icons:any = [];
        if (this._battler && this._battler.isAlive()) {
            icons = this._battler.allIcons();
        }
        if (icons.length > 0) {
            this._animationIndex++;
            if (this._animationIndex >= icons.length) {
                this._animationIndex = 0;
            }
            this._iconIndex = icons[this._animationIndex];
        } else {
            this._animationIndex = 0;
            this._iconIndex = 0;
        }
    };
    updateFrame(): void {
        var pw = Sprite_StateIcon._iconWidth;
        var ph = Sprite_StateIcon._iconHeight;
        var sx = this._iconIndex % 16 * pw;
        var sy = Math.floor(this._iconIndex / 16) * ph;
        this.setFrame(sx, sy, pw, ph);
    };
}

//-----------------------------------------------------------------------------
// Sprite_StateOverlay
//
// The sprite for displaying an overlay image for a state.

 class Sprite_StateOverlay extends Sprite_Base {
    constructor(){
        super();
        this.initialize.apply(this, arguments);
    }
    initialize(): void{
        Sprite_Base.prototype.initialize.call(this);
        this.initMembers();
        this.loadBitmap();
    };
    initMembers(): void{
        this._battler = null;
        this._overlayIndex = 0;
        this._animationCount = 0;
        this._pattern = 0;
        this.anchor.x = 0.5;
        this.anchor.y = 1;
    };
    _battler: Game_Battler;
    _overlayIndex: number;
    _animationCount: number;
    _pattern: number;

    loadBitmap(): void{
        this.bitmap = ImageManager.loadSystem('States');
        this.setFrame(0, 0, 0, 0);
    };
    setup(battler: Game_Battler): void{
        this._battler = battler;
    };
    update(): void{
        Sprite_Base.prototype.update.call(this);
        this._animationCount++;
        if (this._animationCount >= this.animationWait()) {
            this.updatePattern();
            this.updateFrame();
            this._animationCount = 0;
        }
    };
    animationWait(): number{
        return 8;
    };
    updatePattern(): void{
        this._pattern++;
        this._pattern %= 8;
        if (this._battler) {
            this._overlayIndex = this._battler.stateOverlayIndex();
        }
    };
    updateFrame(): void{
        if (this._overlayIndex > 0) {
            var w = 96;
            var h = 96;
            var sx = this._pattern * w;
            var sy = (this._overlayIndex - 1) * h;
            this.setFrame(sx, sy, w, h);
        } else {
            this.setFrame(0, 0, 0, 0);
        }
    };
}

//-----------------------------------------------------------------------------
// Sprite_Weapon
//
// The sprite for displaying a weapon image for attacking.

 class Sprite_Weapon extends Sprite_Base {
    constructor() {
        super();
        this.initialize.apply(this, arguments);
    }
    initialize(): void{
        Sprite_Base.prototype.initialize.call(this);
        this.initMembers();
    };
    initMembers(): void{
        this._weaponImageId = 0;
        this._animationCount = 0;
        this._pattern = 0;
        this.anchor.x = 0.5;
        this.anchor.y = 1;
        this.x = -16;
    };
    _weaponImageId: number;
    _animationCount: number;
    _pattern: number;

    setup(weaponImageId: number): void{
        this._weaponImageId = weaponImageId;
        this._animationCount = 0;
        this._pattern = 0;
        this.loadBitmap();
        this.updateFrame();
    };
    update(): void{
        Sprite_Base.prototype.update.call(this);
        this._animationCount++;
        if (this._animationCount >= this.animationWait()) {
            this.updatePattern();
            this.updateFrame();
            this._animationCount = 0;
        }
    };
    animationWait(): number{
        return 12;
    };
    updatePattern(): void{
        this._pattern++;
        if (this._pattern >= 3) {
            this._weaponImageId = 0;
        }
    };
    loadBitmap(): void{
        var pageId = Math.floor((this._weaponImageId - 1) / 12) + 1;
        if (pageId >= 1) {
            this.bitmap = ImageManager.loadSystem('Weapons' + pageId);
        } else {
            this.bitmap = ImageManager.loadSystem('');
        }
    };
    updateFrame(): void{
        if (this._weaponImageId > 0) {
            var index = (this._weaponImageId - 1) % 12;
            var w = 96;
            var h = 64;
            var sx = (Math.floor(index / 6) * 3 + this._pattern) * w;
            var sy = Math.floor(index % 6) * h;
            this.setFrame(sx, sy, w, h);
        } else {
            this.setFrame(0, 0, 0, 0);
        }
    };
    isPlaying(): boolean{
        return this._weaponImageId > 0;
    };
}

//-----------------------------------------------------------------------------
// Sprite_Balloon
//
// The sprite for displaying a balloon icon.

 class Sprite_Balloon extends Sprite_Base {
    constructor(){
        super();
        this.initialize.apply(this, arguments);
    }
    initialize(): void{
        Sprite_Base.prototype.initialize.call(this);
        this.initMembers();
        this.loadBitmap();
    };
    initMembers(): void{
        this._balloonId = 0;
        this._duration = 0;
        this.anchor.x = 0.5;
        this.anchor.y = 1;
        this.z = 7;
    };
    _balloonId: number;
    _duration: number;

    loadBitmap(): void{
        this.bitmap = ImageManager.loadSystem('Balloon');
        this.setFrame(0, 0, 0, 0);
    };
    setup(balloonId: number): void{
        this._balloonId = balloonId;
        this._duration = 8 * this.speed() + this.waitTime();
    };
    update(): void{
        Sprite_Base.prototype.update.call(this);
        if (this._duration > 0) {
            this._duration--;
            if (this._duration > 0) {
                this.updateFrame();
            }
        }
    };
    updateFrame(): void{
        var w = 48;
        var h = 48;
        var sx = this.frameIndex() * w;
        var sy = (this._balloonId - 1) * h;
        this.setFrame(sx, sy, w, h);
    };
    speed(): number{
        return 8;
    };
    waitTime(): number{
        return 12;
    };
    frameIndex(): number{
        var index = (this._duration - this.waitTime()) / this.speed();
        return 7 - Math.max(Math.floor(index), 0);
    };
    isPlaying(): boolean{
        return this._duration > 0;
    };
}

//-----------------------------------------------------------------------------
// Sprite_Picture
//
// The sprite for displaying a picture.

 class Sprite_Picture extends Sprite {
    constructor(pictureId: number){
        super();
        this.initialize.apply(this, arguments);
    }
    initialize(pictureId: number|any): void {
        Sprite.prototype.initialize.call(this);
        this._pictureId = pictureId;
        this._pictureName = '';
        this._isPicture = true;
        this.update();
    };
    _pictureId: number;
    _pictureName: string;
    _isPicture: boolean;

    picture(): Game_Picture {
        return $gameScreen.picture(this._pictureId);
    };
    update(): void{
        Sprite.prototype.update.call(this);
        this.updateBitmap();
        if (this.visible) {
            this.updateOrigin();
            this.updatePosition();
            this.updateScale();
            this.updateTone();
            this.updateOther();
        }
    };
    updateBitmap(): void{
        var picture = this.picture();
        if (picture) {
            var pictureName = picture.name();
            if (this._pictureName !== pictureName) {
                this._pictureName = pictureName;
                this.loadBitmap();
            }
            this.visible = true;
        } else {
            this._pictureName = '';
            this.bitmap = null;
            this.visible = false;
        }
    };
    updateOrigin(): void{
        var picture = this.picture();
        if (picture.origin() === 0) {
            this.anchor.x = 0;
            this.anchor.y = 0;
        } else {
            this.anchor.x = 0.5;
            this.anchor.y = 0.5;
        }
    };
    updatePosition(): void{
        var picture = this.picture();
        this.x = Math.floor(picture.x());
        this.y = Math.floor(picture.y());
    };
    updateScale(): void{
        var picture = this.picture();
        this.scale.x = picture.scaleX() / 100;
        this.scale.y = picture.scaleY() / 100;
    };
    updateTone(): void{
        var picture = this.picture();
        if (picture.tone()) {
            this.setColorTone(picture.tone());
        } else {
            this.setColorTone([0, 0, 0, 0]);
        }
    };
    updateOther(): void{
        var picture = this.picture();
        this.opacity = picture.opacity();
        this.blendMode = picture.blendMode();
        this.rotation = picture.angle() * Math.PI / 180;
    };
    loadBitmap(): void{
        this.bitmap = ImageManager.loadPicture(this._pictureName);
    };
}

//-----------------------------------------------------------------------------
// Sprite_Timer
//
// The sprite for displaying the timer.

 class Sprite_Timer extends Sprite {
    constructor(){
        super();
        this.initialize.apply(this, arguments);
    }
    initialize(): void{
        Sprite.prototype.initialize.call(this);
        this._seconds = 0;
        this.createBitmap();
        this.update();
    };
    _seconds: number;

    createBitmap(): void{
        this.bitmap = new Bitmap(96, 48);
        this.bitmap.fontSize = 32;
    };
    update(): void{
        Sprite.prototype.update.call(this);
        this.updateBitmap();
        this.updatePosition();
        this.updateVisibility();
    };
    updateBitmap(): void{
        if (this._seconds !== $gameTimer.seconds()) {
            this._seconds = $gameTimer.seconds();
            this.redraw();
        }
    };
    redraw(): void{
        var text = this.timerText();
        var width = this.bitmap.width;
        var height = this.bitmap.height;
        this.bitmap.clear();
        this.bitmap.drawText(text, 0, 0, width, height, 'center');
    };
    timerText(): string{
        var min = Math.floor(this._seconds / 60) % 60;
        var sec = this._seconds % 60;
        return min.padZero(2) + ':' + sec.padZero(2);
    };
    updatePosition(): void{
        this.x = Graphics.width - this.bitmap.width;
        this.y = 0;
    };
    updateVisibility(): void{
        this.visible = $gameTimer.isWorking();
    };
}

//-----------------------------------------------------------------------------
// Sprite_Destination
//
// The sprite for displaying the destination place of the touch input.

 class Sprite_Destination extends Sprite {
    constructor(){
        super();
        this.initialize.apply(this, arguments);
    }
    initialize(): void{
        Sprite.prototype.initialize.call(this);
        this.createBitmap();
        this._frameCount = 0;
    };
    _frameCount: number;

    update(): void{
        Sprite.prototype.update.call(this);
        if ($gameTemp.isDestinationValid()){
            this.updatePosition();
            this.updateAnimation();
            this.visible = true;
        } else {
            this._frameCount = 0;
            this.visible = false;
        }
    };
    createBitmap(): void{
        var tileWidth = $gameMap.tileWidth();
        var tileHeight = $gameMap.tileHeight();
        this.bitmap = new Bitmap(tileWidth, tileHeight);
        this.bitmap.fillAll('white');
        this.anchor.x = 0.5;
        this.anchor.y = 0.5;
        this.blendMode = Graphics.BLEND_ADD;
    };
    updatePosition(): void{
        var tileWidth = $gameMap.tileWidth();
        var tileHeight = $gameMap.tileHeight();
        var x = $gameTemp.destinationX();
        var y = $gameTemp.destinationY();
        this.x = ($gameMap.adjustX(x) + 0.5) * tileWidth;
        this.y = ($gameMap.adjustY(y) + 0.5) * tileHeight;
    };
    updateAnimation(): void{
        this._frameCount++;
        this._frameCount %= 20;
        this.opacity = (20 - this._frameCount) * 6;
        this.scale.x = 1 + this._frameCount / 20;
        this.scale.y = this.scale.x;
    };
}

//-----------------------------------------------------------------------------
// Spriteset_Base
//
// The superclass of Spriteset_Map and Spriteset_Battle.

 class Spriteset_Base extends Sprite {
    constructor(){
        super();
        this.initialize.apply(this, arguments);
    }
    initialize(): void{
        Sprite.prototype.initialize.call(this);
        this.setFrame(0, 0, Graphics.width, Graphics.height);
        this._tone = [0, 0, 0, 0];
        this.opaque = true;
        this.createLowerLayer();
        this.createToneChanger();
        this.createUpperLayer();
        this.update();
    };
    _tone: number[]|any;
    opaque: boolean;

    createLowerLayer(): void {
        this.createBaseSprite();
    };
    createUpperLayer(): void{
        this.createPictures();
        this.createTimer();
        this.createScreenSprites();
    };
    update(): void{
        Sprite.prototype.update.call(this);
        this.updateScreenSprites();
        this.updateToneChanger();
        this.updatePosition();
    };
    createBaseSprite(): void{
        this._baseSprite = new Sprite();
        this._baseSprite.setFrame(0, 0, this.width, this.height);
        this._blackScreen = new ScreenSprite();
        this._blackScreen.opacity = 255;
        this.addChild(this._baseSprite);
        this._baseSprite.addChild(this._blackScreen);
    };
    _baseSprite: Sprite;
    _blackScreen: ScreenSprite;
    createToneChanger(): void{
        if (Graphics.isWebGL()) {
            this.createWebGLToneChanger();
        } else {
            this.createCanvasToneChanger();
        }
    };
    createWebGLToneChanger(): void{
        var margin = 48;
        var width = Graphics.width + margin * 2;
        var height = Graphics.height + margin * 2;
        this._toneFilter = new ToneFilter();
        this._baseSprite.filters = [this._toneFilter];
        this._baseSprite.filterArea = new Rectangle(-margin, -margin, width, height);
    };
     _toneFilter: ToneFilter;
    createCanvasToneChanger(): void{
        this._toneSprite = new ToneSprite();
        this.addChild(this._toneSprite);
    };
    _toneSprite: ToneSprite;
    createPictures(): void{
        var width = Graphics.boxWidth;
        var height = Graphics.boxHeight;
        var x = (Graphics.width - width) / 2;
        var y = (Graphics.height - height) / 2;
        this._pictureContainer = new Sprite();
        this._pictureContainer.setFrame(x, y, width, height);
        for (var i = 1; i <= $gameScreen.maxPictures(); i++) {
            this._pictureContainer.addChild(new Sprite_Picture(i));
        }
        this.addChild(this._pictureContainer);
    };
    _pictureContainer: Sprite;
    createTimer(): void{
        this._timerSprite = new Sprite_Timer();
        this.addChild(this._timerSprite);
    };
    _timerSprite: Sprite_Timer;
    createScreenSprites(): void{
        this._flashSprite = new ScreenSprite();
        this._fadeSprite = new ScreenSprite();
        this.addChild(this._flashSprite);
        this.addChild(this._fadeSprite);
    };
    _flashSprite: ScreenSprite;
    _fadeSprite: ScreenSprite;
    updateScreenSprites(): void{
        var color = $gameScreen.flashColor();
        this._flashSprite.setColor(color[0], color[1], color[2]);
        this._flashSprite.opacity = color[3];
        this._fadeSprite.opacity = 255 - $gameScreen.brightness();
    };
    updateToneChanger(): void{
        var tone = $gameScreen.tone();
        if (!this._tone.equals(tone)) {
            this._tone = tone.clone();
            if (Graphics.isWebGL()) {
                this.updateWebGLToneChanger();
            } else {
                this.updateCanvasToneChanger();
            }
        }
    };
    updateWebGLToneChanger(): void{
        var tone = this._tone;
        this._toneFilter.reset();
        this._toneFilter.adjustTone(tone[0], tone[1], tone[2]);
        this._toneFilter.adjustSaturation(-tone[3]);
    };
    updateCanvasToneChanger(): void{
        var tone = this._tone;
        this._toneSprite.setTone(tone[0], tone[1], tone[2], tone[3]);
    };
    updatePosition(): void{
        var screen = $gameScreen;
        var scale = screen.zoomScale();
        this.scale.x = scale;
        this.scale.y = scale;
        this.x = Math.round(-screen.zoomX() * (scale - 1));
        this.y = Math.round(-screen.zoomY() * (scale - 1));
        this.x += Math.round(screen.shake());
    };
}

//-----------------------------------------------------------------------------
// Spriteset_Map
//
// The set of sprites on the map screen.

 class Spriteset_Map extends Spriteset_Base {
    constructor(){
        super();
        this.initialize.apply(this, arguments);
    }
    initialize(): void {
        Spriteset_Base.prototype.initialize.call(this);
    };

    createLowerLayer(): void {
        Spriteset_Base.prototype.createLowerLayer.call(this);
        this.createParallax();
        this.createTilemap();
        this.createCharacters();
        this.createShadow();
        this.createDestination();
        this.createWeather();
    };
    update(): void {
        Spriteset_Base.prototype.update.call(this);
        this.updateTileset();
        this.updateParallax();
        this.updateTilemap();
        this.updateShadow();
        this.updateWeather();
    };
    hideCharacters(): void {
        for (var i = 0; i < this._characterSprites.length; i++) {
            var sprite = this._characterSprites[i];
            if (!sprite.isTile()) {
                sprite.hide();
            }
        }
    };
    createParallax(): void {
        this._parallax = new TilingSprite();
        this._parallax.move(0, 0, Graphics.width, Graphics.height);
        this._baseSprite.addChild(this._parallax);
    };
    
    _parallax: TilingSprite|any;
    createTilemap(): void {
        if (Graphics.isWebGL()) {
            this._tilemap = new ShaderTilemap();
        } else {
            this._tilemap = new Tilemap();
        }
        this._tilemap.tileWidth = $gameMap.tileWidth();
        this._tilemap.tileHeight = $gameMap.tileHeight();
        this._tilemap.setData($gameMap.width(), $gameMap.height(), $gameMap.data());
        this._tilemap.horizontalWrap = $gameMap.isLoopHorizontal();
        this._tilemap.verticalWrap = $gameMap.isLoopVertical();
        this.loadTileset();
        this._baseSprite.addChild(this._tilemap);
    };
    _tilemap: Tilemap;
    loadTileset(): void {
        this._tileset = $gameMap.tileset();
        if (this._tileset) {
            var tilesetNames = this._tileset.tilesetNames;
            for (var i = 0; i < tilesetNames.length; i++) {
                this._tilemap.bitmaps[i] = ImageManager.loadTileset(tilesetNames[i]);
            }
            var newTilesetFlags = $gameMap.tilesetFlags();
            this._tilemap.refreshTileset();
            if (!this._tilemap.flags.equals(newTilesetFlags)) {
                this._tilemap.refresh();
            }
            this._tilemap.flags = newTilesetFlags;
        }
    };
    _tileset: RPGMakerMV.DataTileset;
    createCharacters(): void {
        this._characterSprites = [];
        $gameMap.events().forEach((event: Game_CharacterBase) => {
            this._characterSprites.push(new Sprite_Character(event));
        },);
        $gameMap.vehicles().forEach((vehicle: Game_CharacterBase) => {
            this._characterSprites.push(new Sprite_Character(vehicle));
        });
        $gamePlayer.followers().reverseEach((follower: Game_CharacterBase) => {
            this._characterSprites.push(new Sprite_Character(follower));
        });
        this._characterSprites.push(new Sprite_Character($gamePlayer));
        for (var i = 0; i < this._characterSprites.length; i++) {
            this._tilemap.addChild(this._characterSprites[i]);
        }
    };
    _characterSprites: Sprite_Character[];
    createShadow(): void {
        this._shadowSprite = new Sprite();
        this._shadowSprite.bitmap = ImageManager.loadSystem('Shadow1');
        this._shadowSprite.anchor.x = 0.5;
        this._shadowSprite.anchor.y = 1;
        this._shadowSprite.z = 6;
        this._tilemap.addChild(this._shadowSprite);
    };
    _shadowSprite: Sprite;
    createDestination(): void {
        this._destinationSprite = new Sprite_Destination();
        this._destinationSprite.z = 9;
        this._tilemap.addChild(this._destinationSprite);
    };
    _destinationSprite: Sprite_Destination;
    createWeather(): void{
        this._weather = new Weather();
        this.addChild(this._weather);
    };
    _weather: Weather;
    updateTileset(): void{
        if (this._tileset !== $gameMap.tileset()) {
            this.loadTileset();
        }
    };

    /*
    * Simple fix for canvas parallax issue, destroy old parallax and readd to  the tree.
    */
    _canvasReAddParallax(): void{
        var index = this._baseSprite.children.indexOf(this._parallax);
        this._baseSprite.removeChild(this._parallax);
        this._parallax = new TilingSprite();
        this._parallax.move(0, 0, Graphics.width, Graphics.height);
        this._parallax.bitmap = ImageManager.loadParallax(this._parallaxName);
        this._baseSprite.addChildAt(this._parallax,index);
    };

    updateParallax(): void{
        if (this._parallaxName !== $gameMap.parallaxName()) {
            this._parallaxName = $gameMap.parallaxName();
    
            if (this._parallax.bitmap && Graphics.isWebGL() != true) {
                this._canvasReAddParallax();
            } else {
                this._parallax.bitmap = ImageManager.loadParallax(this._parallaxName);
            }
        }
        if (this._parallax.bitmap) {
            this._parallax.origin.x = $gameMap.parallaxOx();
            this._parallax.origin.y = $gameMap.parallaxOy();
        }
    };
    _parallaxName: string;
    updateTilemap(): void{
        this._tilemap.origin.x = $gameMap.displayX() * $gameMap.tileWidth();
        this._tilemap.origin.y = $gameMap.displayY() * $gameMap.tileHeight();
    };
    updateShadow(): void{
        var airship = $gameMap.airship();
        this._shadowSprite.x = airship.shadowX();
        this._shadowSprite.y = airship.shadowY();
        this._shadowSprite.opacity = airship.shadowOpacity();
    };
    updateWeather(): void{
        this._weather.type = $gameScreen.weatherType();
        this._weather.power = $gameScreen.weatherPower();
        this._weather.origin.x = $gameMap.displayX() * $gameMap.tileWidth();
        this._weather.origin.y = $gameMap.displayY() * $gameMap.tileHeight();
    };
}

//-----------------------------------------------------------------------------
// Spriteset_Battle
//
// The set of sprites on the battle screen.

 class Spriteset_Battle extends Spriteset_Base {
    constructor(){
        super();
        this.initialize.apply(this, arguments);
    }
    initialize(): void {
        Spriteset_Base.prototype.initialize.call(this);
        this._battlebackLocated = false;
    };
    _battlebackLocated: boolean;

    createLowerLayer(): void {
        Spriteset_Base.prototype.createLowerLayer.call(this);
        this.createBackground();
        this.createBattleField();
        this.createBattleback();
        this.createEnemies();
        this.createActors();
    };
    createBackground(): void{
        this._backgroundSprite = new Sprite();
        this._backgroundSprite.bitmap = SceneManager.backgroundBitmap();
        this._baseSprite.addChild(this._backgroundSprite);
    };
    _backgroundSprite: Sprite;
    update(): void{
        Spriteset_Base.prototype.update.call(this);
        this.updateActors();
        this.updateBattleback();
    };
    createBattleField(): void{
        var width = Graphics.boxWidth;
        var height = Graphics.boxHeight;
        var x = (Graphics.width - width) / 2;
        var y = (Graphics.height - height) / 2;
        this._battleField = new Sprite();
        this._battleField.setFrame(x, y, width, height);
        this._battleField.x = x;
        this._battleField.y = y;
        this._baseSprite.addChild(this._battleField);
    };
    _battleField: Sprite;
    createBattleback(): void{
        var margin = 32;
        var x = -this._battleField.x - margin;
        var y = -this._battleField.y - margin;
        var width = Graphics.width + margin * 2;
        var height = Graphics.height + margin * 2;
        this._back1Sprite = new TilingSprite();
        this._back2Sprite = new TilingSprite();
        this._back1Sprite.bitmap = this.battleback1Bitmap();
        this._back2Sprite.bitmap = this.battleback2Bitmap();
        this._back1Sprite.move(x, y, width, height);
        this._back2Sprite.move(x, y, width, height);
        this._battleField.addChild(this._back1Sprite);
        this._battleField.addChild(this._back2Sprite);
    };
    _back1Sprite: TilingSprite|any;
    _back2Sprite: TilingSprite|any;
    updateBattleback(): void {
        if (!this._battlebackLocated) {
            this.locateBattleback();
            this._battlebackLocated = true;
        }
    };
    locateBattleback(): void {
        var width = this._battleField.width;
        var height = this._battleField.height;
        var sprite1 = this._back1Sprite;
        var sprite2 = this._back2Sprite;
        sprite1.origin.x = sprite1.x + (sprite1.bitmap.width - width) / 2;
        sprite2.origin.x = sprite1.y + (sprite2.bitmap.width - width) / 2;
        if ($gameSystem.isSideView()) {
            sprite1.origin.y = sprite1.x + sprite1.bitmap.height - height;
            sprite2.origin.y = sprite1.y + sprite2.bitmap.height - height;
        }
    };
    battleback1Bitmap(): Bitmap {
        return ImageManager.loadBattleback1(this.battleback1Name());
    };
    battleback2Bitmap(): Bitmap {
        return ImageManager.loadBattleback2(this.battleback2Name());
    };
    battleback1Name(): string{
        if (BattleManager.isBattleTest()) {
            return $dataSystem.battleback1Name;
        } else if ($gameMap.battleback1Name()) {
            return $gameMap.battleback1Name();
        } else if ($gameMap.isOverworld()) {
            return this.overworldBattleback1Name();
        } else {
            return '';
        }
    };
    battleback2Name(): string{
        if (BattleManager.isBattleTest()) {
            return $dataSystem.battleback2Name;
        } else if ($gameMap.battleback2Name()) {
            return $gameMap.battleback2Name();
        } else if ($gameMap.isOverworld()) {
            return this.overworldBattleback2Name();
        } else {
            return '';
        }
    };
    overworldBattleback1Name(): string{
        if ($gameMap.battleback1Name() === '') return '';
        if ($gamePlayer.isInVehicle()) {
            return this.shipBattleback1Name();
        } else {
            return this.normalBattleback1Name();
        }
    };
    overworldBattleback2Name(): string{
        if ($gameMap.battleback2Name() === '') return '';
        if ($gamePlayer.isInVehicle()) {
            return this.shipBattleback2Name();
        } else {
            return this.normalBattleback2Name();
        }
    };
    normalBattleback1Name(): string {
        return (this.terrainBattleback1Name(this.autotileType(1)) ||
                this.terrainBattleback1Name(this.autotileType(0)) ||
                this.defaultBattleback1Name());
    };
    normalBattleback2Name(): string {
        return (this.terrainBattleback2Name(this.autotileType(1)) ||
                this.terrainBattleback2Name(this.autotileType(0)) ||
                this.defaultBattleback2Name());
    };
    terrainBattleback1Name(type: number): string {
        switch (type) {
        case 24: case 25:
            return 'Wasteland';
        case 26: case 27:
            return 'DirtField';
        case 32: case 33:
            return 'Desert';
        case 34:
            return 'Lava1';
        case 35:
            return 'Lava2';
        case 40: case 41:
            return 'Snowfield';
        case 42:
            return 'Clouds';
        case 4: case 5:
            return 'PoisonSwamp';
        default:
            return null;
        }
    };
    terrainBattleback2Name(type: number): string {
        switch (type) {
        case 20: case 21:
            return 'Forest';
        case 22: case 30: case 38:
            return 'Cliff';
        case 24: case 25: case 26: case 27:
            return 'Wasteland';
        case 32: case 33:
            return 'Desert';
        case 34: case 35:
            return 'Lava';
        case 40: case 41:
            return 'Snowfield';
        case 42:
            return 'Clouds';
        case 4: case 5:
            return 'PoisonSwamp';
        }
    };
    defaultBattleback1Name(): string {
        return 'Grassland';
    };
    defaultBattleback2Name(): string {
        return 'Grassland';
    };
    shipBattleback1Name(): string {
        return 'Ship';
    };
    shipBattleback2Name(): string {
        return 'Ship';
    };
    autotileType(z: number): number {
        return $gameMap.autotileType($gamePlayer.x, $gamePlayer.y, z);
    };
    createEnemies(): void {
        var enemies = $gameTroop.members();
        var sprites = [];
        for (var i = 0; i < enemies.length; i++) {
            sprites[i] = new Sprite_Enemy(enemies[i]);
        }
        sprites.sort(this.compareEnemySprite.bind(this));
        for (var j = 0; j < sprites.length; j++) {
            this._battleField.addChild(sprites[j]);
        }
        this._enemySprites = sprites;
    };
    _enemySprites: Sprite_Enemy[];
    compareEnemySprite(a: Sprite_Enemy, b: Sprite_Enemy): number {
        if (a.y !== b.y) {
            return a.y - b.y;
        } else {
            return b.spriteId - a.spriteId;
        }
    };
    createActors(): void {
        this._actorSprites = [];
        for (var i = 0; i < $gameParty.maxBattleMembers(); i++) {
            this._actorSprites[i] = new Sprite_Actor();
            this._battleField.addChild(this._actorSprites[i]);
        }
    };
    _actorSprites: Sprite_Actor[]|any;
    updateActors(): void {
        var members = $gameParty.battleMembers();
        for (var i = 0; i < this._actorSprites.length; i++) {
            this._actorSprites[i].setBattler(members[i]);
        }
    };
    battlerSprites(): Sprite_Battler[] {
        return this._enemySprites.concat(this._actorSprites);
    };
    isAnimationPlaying(): boolean {
        return this.battlerSprites().some(function(sprite) {
            return sprite.isAnimationPlaying();
        });
    };
    isEffecting(): boolean {
        return this.battlerSprites().some(function(sprite) {
            return sprite.isEffecting();
        });
    };
    isAnyoneMoving(): boolean {
        return this.battlerSprites().some(function(sprite) {
            return sprite.isMoving();
        });
    };
    isBusy(): boolean {
        return this.isAnimationPlaying() || this.isAnyoneMoving();
    };
}
